/*************************************************************
*
* VOXEL.H
*
* Generic voxel support ('vox')
*************************************************************/

#ifndef _VOXEL_H_
#define _VOXEL_H_


class voxGRID {
public:
   voxGRID() : nVoxel(m3dVIntZero), voxSize(m3dVZero) {};

   m3dVINT   nVoxel;
   m3dBOX    bbox;
   m3dV      voxSize;

   //
   // Functions
   //
   int      GetNVoxelX (void) const  { return nVoxel.x; }
   int      GetNVoxelY (void) const  { return nVoxel.y; }
   int      GetNVoxelZ (void) const  { return nVoxel.z; }

   float    GetVoxSizeX(void) const  { return voxSize.x; }
   float    GetVoxSizeY(void) const  { return voxSize.y; }
   float    GetVoxSizeZ(void) const  { return voxSize.z; }
   void     SetVoxSize (float x, float y, float z) { voxSize.x = x; voxSize.y = y; voxSize.z = z; }

   int      GetNVoxels        (void) const;
   BOOL     IsValidInd        (int x, int y, int z) const;
   BOOL     CalcVoxSize       (void);  // bbox & # of voxels are setup; calc voxel size
   void     CalcNVoxel        (void);  // bbox & size of voxels are setup; calc # of voxels
   void     GetPosInd         (const m3dV *pos, int *x, int *y, int *z, BOOL isClamp = TRUE) const;
   void     LinearInd2Ind     (int linInd, int *x, int *y, int *z);
   void     ClampIndices      (int *x, int *y, int *z) const;
   int      GetPosLinearInd   (m3dV *pos);
   void     CalcVoxBBox       (int x, int y, int z, m3dBOX *pB);

   void     BuildNewGridUsingVoxel (int x, int y, int z, voxGRID *pB, int nx = 1, int ny = 1, int nz = 1);

   __INLINE int GetLinearInd  (int x, int y, int z);
};

//
// Generic Voxel Grid Iterator
//

class voxITER {
public:
   enum TYPE {
      TYPE_PURE,
      TYPE_BOX
   };
private:
   TYPE type;
protected:
   voxGRID   *pVG;
   float      distCur;
public:
   voxITER (voxGRID *_pVG, TYPE _type) : type(_type), pVG(_pVG), distCur(0.f) {}
   virtual ~voxITER (void) {}
   virtual void ApplyCS (m3dMATR *pMatrW2L) = 0;
   virtual BOOL Start   (void) = 0;
   virtual BOOL Next    (int *indList, int *nInd, int indNumMax) = 0;

   inline float GetCurDist   (void) { return distCur; }
   inline void  SetType(TYPE _type) {type = _type;}
   inline TYPE  GetType()           {return type;}
};

//
// BOX Voxel Grid Iterator
//
class voxITER_BOX : public voxITER {
protected:
   m3dBOX  box;
   m3dVINT from,     to;
   float   step;
   m3dVINT fromNext, toNext;
public:
   voxITER_BOX (voxGRID *_pVG) : voxITER(_pVG, voxITER::TYPE_BOX) {}
   virtual void ApplyCS (m3dMATR *pMatrW2L);
   virtual BOOL Start   (void);
   virtual BOOL Next    (int *indList, int *nInd, int indNumMax);
   BOOL         SetBox  (const m3dBOX *pBB);
   m3dBOX*      GetBox  (void)        { return &box;    }

   m3dVINT      GetFrom (void)        { return from; }
   m3dVINT      GetTo   (void)        { return to; }
   voxGRID*     GetVG   (void)        { return pVG; }
};

class voxITER_BOX_SYMMETRICAL : public voxITER {
protected:
   m3dBOX  box;
   m3dVINT from,     to;
   float   step;
   m3dVINT fromNext, toNext;
public:
   voxITER_BOX_SYMMETRICAL (voxGRID *_pVG) : voxITER(_pVG, voxITER::TYPE_BOX) {}
   virtual void ApplyCS (m3dMATR *pMatrW2L);
   virtual BOOL Start   (void);
   virtual BOOL Next    (int *indList, int *nInd, int indNumMax);
   BOOL         SetBox  (m3dBOX *pBB);
   m3dBOX*      GetBox  (void)        { return &box;    }
};

//
// Sphere Voxel Grid Iterator
//
class voxITER_SPH : public voxITER_BOX_SYMMETRICAL {
public:
   voxITER_SPH (voxGRID *_pVG) : voxITER_BOX_SYMMETRICAL(_pVG) {}
   virtual void ApplyCS (m3dMATR *pMatrW2L);
   void         SetSph  (m3dV *org, float radius)  { m3dBOX box; box.MakePointPoint(org, org); box.Expand(radius); SetBox(&box); }
};
//
// Ray Voxel Grid Iterator
//
class voxITER_RAY : public voxITER {
protected:
   m3dV    vFrom, vTo;

   int     fromX, fromY, fromZ; // starting voxel indices
   int     toX, toY, toZ;       // finishing voxel indices
   float   dtX, dtY, dtZ;       // time to cross layer of width 1
   float   tX, tY, tZ;          // time before hit in nearest layer bound
   float   ctX, ctY, ctZ;       // coeff to convert tX to dist along the ray
   int     vX, vY, vZ;          // voxel index
   int     dvX, dvY, dvZ;       // voxel index increments
   int     nVoxels;             // number of voxels in list
   int     i;                   // lc: number of voxel in list
public:
   voxITER_RAY (voxGRID *_pVG) : voxITER(_pVG, TYPE_PURE) {}
   virtual void ApplyCS (m3dMATR *pMatrW2L);
   virtual BOOL Start   (void);
   virtual BOOL Next    (int *indList, int *nInd, int indNumMax);
   BOOL         SetRay  (m3dV *_vFrom, m3dV *_vTo);
};
//
// Cyl Voxel Grid Iterator
//
class voxITER_CYL : public voxITER_RAY {
   float   radius;
public:
   voxITER_CYL (voxGRID *_pVG) : voxITER_RAY(_pVG) {}
   virtual BOOL Start   (void);
   virtual BOOL Next    (int *indList, int *nInd, int indNumMax);
   BOOL         SetCyl  (m3dV *_vFrom, m3dV *_vTo, float _radius);
};

//
// BOX Voxel Grid Iterator
//
class voxITER_MIN_DIST : public voxITER_BOX {
public:
   voxITER_MIN_DIST (voxGRID *_pVG) : voxITER_BOX(_pVG) {}
   virtual BOOL Start   (void);
   void         SetPoint(m3dV *_point);
};





/**********************************************************
* voxGRID::GetLinearInd()
*
**********************************************************/
__INLINE int voxGRID::GetLinearInd (int x, int y, int z)
{
   ASSERT(IsValidInd(x, y, z));
   return z + y*GetNVoxelZ() + x*GetNVoxelY()*GetNVoxelZ();
}

//
// Global functions
//
extern int voxCalcNVoxel (float sizeBBoxSide, float sizeVox); // the same along a single axis

#endif // _VOXEL_H_

//
// End of file VOXEL.H
//
